/*
 * Copyright (c) 2018-2999 湖南洛云网络科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.binarywang.wxpay.service.WxPayService;
import com.yami.shop.bean.app.param.PayParam;
import com.yami.shop.bean.dto.OrderRefundDto;
import com.yami.shop.bean.enums.OrderStatus;
import com.yami.shop.bean.enums.OrderType;
import com.yami.shop.bean.event.CheckGroupOrderEvent;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.event.CheckSecKillOrderEvent;
import com.yami.shop.bean.pay.RefundInfoDto;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.enums.PayType;
import com.yami.shop.bean.event.PaySuccessOrderEvent;
import com.yami.shop.bean.pay.PayInfoDto;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.Arith;
import com.yami.shop.config.WxConfig;
import com.yami.shop.dao.OrderMapper;
import com.yami.shop.dao.OrderSettlementMapper;
import com.yami.shop.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lgh on 2018/09/15.
 */
@Slf4j
@Service
@AllArgsConstructor
public class PayServiceImpl implements PayService {

    private final OrderMapper orderMapper;
    private final OrderSettlementMapper orderSettlementMapper;
    private final OrderSettlementService orderSettlementService;
    private final ApplicationContext applicationContext;
    private final ApplicationEventPublisher eventPublisher;
    private final WxConfig wxConfig;
    private final NotifyTemplateService notifyTemplateService;
    private final Snowflake snowflake;
    private final RefundOrderSettlementService refundOrderSettlementService;
    private final PayManagerService payManagerService;
    private final OrderSettlementHistoryService orderSettlementHistoryService;

    /**
     * 不同的订单号，同一个支付流水号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayInfoDto pay(String userId, PayParam payParam) {
        // 支付单号
        String payNo = String.valueOf(snowflake.nextId());
        String[] orderNumbers = payParam.getOrderNumbers().split(StrUtil.COMMA);
        // 应支付的总金额
        double payAmount = 0.0;
        double payScore = 0;
        int isScore = 0;
        // 修改订单信息
        for (String orderNumber : orderNumbers) {
            OrderSettlement orderSettlement = orderSettlementMapper.selectOne(
                    new LambdaQueryWrapper<OrderSettlement>()
                            .eq(OrderSettlement::getUserId,userId)
                            .eq(OrderSettlement::getOrderNumber,orderNumber)
            );
            if(Objects.isNull(orderSettlement)){
                // 订单不存在
                throw new YamiShopBindException("yami.address.deleted");
            }
            if (Objects.equals(orderSettlement.getPayStatus(), 1)) {
                // 支付失败，订单不在未支付状态
                throw new YamiShopBindException("yami.order.pay.fail");
            }
            Order order = orderMapper.getOrderByOrderNumber(orderNumber);
//            if (!Objects.equals(order.getStatus(), OrderStatus.UNPAY.value())) {
//                // 支付失败，订单不在未支付状态
//                throw new YamiShopBindException("yami.order.pay.fail");
//            }
            order.setPayType(payParam.getPayType());
            orderMapper.updateById(order);


            orderSettlement.setUserId(userId);
            orderSettlement.setOrderNumber(orderNumber);
            payAmount = Arith.add(payAmount, orderSettlement.getPayAmount());
            payScore += orderSettlement.getPayScore() == null ? 0:orderSettlement.getPayScore();
            orderSettlementMapper.updateByOrderNumberAndUserId(orderSettlement);

            OrderSettlementHistory orderSettlementHistory = orderSettlementHistoryService.getOne(new LambdaQueryWrapper<OrderSettlementHistory>()
                    .eq(OrderSettlementHistory::getPayNo, payNo).eq(OrderSettlementHistory::getUserId, userId).eq(OrderSettlementHistory::getOrderNumber, orderNumber));
            if (Objects.isNull(orderSettlementHistory)) {
                orderSettlementHistory = new OrderSettlementHistory();
                orderSettlementHistory.setSettlementId(orderSettlement.getSettlementId());
                orderSettlementHistory.setUserId(orderSettlement.getUserId());
                orderSettlementHistory.setIsClearing(orderSettlement.getIsClearing());
                orderSettlementHistory.setCreateTime(orderSettlement.getCreateTime());
                orderSettlementHistory.setOrderNumber(orderSettlement.getOrderNumber());
                orderSettlementHistory.setPayAmount(orderSettlement.getPayAmount());
                orderSettlementHistory.setPayStatus(orderSettlement.getPayStatus());
                orderSettlementHistory.setVersion(orderSettlement.getVersion());
                orderSettlementHistory.setPayScore(orderSettlement.getPayScore());
                orderSettlementHistory.setChangeAmountVersion(orderSettlement.getChangeAmountVersion());
            }
            orderSettlementHistory.setPayNo(payNo);
            orderSettlementHistory.setPayType(payParam.getPayType());
            orderSettlementHistory.setUserId(userId);
            orderSettlementHistory.setOrderNumber(orderNumber);
            orderSettlementHistoryService.saveOrUpdate(orderSettlementHistory);

            // 普通订单创建时间经过限定订单超时分钟，如果为true则早于当前时间表示过期，抛出异常
//            boolean isExpired = !DateUtil.isExpired(order.getCreateTime(), DateField.MINUTE, Constant.ORDER_MAX_TIME, new Date())
            boolean isExpired = !DateUtil.offsetMinute(order.getCreateTime(), Constant.ORDER_MAX_TIME).after(new Date());
//            if(isExpired){
//                // 秒杀订单已经过期，无法进行支付
//                throw new YamiShopBindException("yami.order.expired");
//            }
//            // 如果是秒杀订单,还需判断秒杀订单有没有过期
//            if(Objects.equals(order.getOrderType(),OrderType.SECKILL.value())){
//                applicationContext.publishEvent(new CheckSecKillOrderEvent(order));
//            }
//            // 如果是团购订单,还需判断团购订单有没有过期
//            if(Objects.equals(order.getOrderType(),OrderType.GROUP.value())){
//                applicationContext.publishEvent(new CheckGroupOrderEvent(order));
//            }
        }
        //如果金额小于0.01 支付积分大于0则为纯积分支付
        if(payAmount < 0.01 && payScore > 0){
            isScore = 1;
            paySuccess(payNo, null, PayType.SCOREPAY.value());
        }
        PayInfoDto payInfoDto = new PayInfoDto();
        payInfoDto.setBody("商城订单");
        payInfoDto.setPayAmount(payAmount);
        payInfoDto.setPayNo(payNo);
        payInfoDto.setIsScore(isScore);
        return payInfoDto;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Order> paySuccess(String payNo, String bizPayNo, Integer payType) {
        List<OrderSettlementHistory> orderSettlementHistories = orderSettlementHistoryService.list(new LambdaQueryWrapper<OrderSettlementHistory>().eq(OrderSettlementHistory::getPayNo, payNo));
        OrderSettlementHistory temp = orderSettlementHistories.get(0);
        OrderSettlement temp2 = orderSettlementService.getOne(new LambdaQueryWrapper<OrderSettlement>().eq(OrderSettlement::getUserId, temp.getUserId()).eq(OrderSettlement::getOrderNumber, temp.getOrderNumber()));
        if (Objects.isNull(temp2.getPayNo())) {
            if (Objects.equals(temp.getChangeAmountVersion(), temp2.getChangeAmountVersion())) {
                List<OrderSettlement> orderSettlementList = new ArrayList<>();
                for (OrderSettlementHistory orderSettlementHistory : orderSettlementHistories) {
                    OrderSettlement orderSettlement = orderSettlementMapper.selectOne(new LambdaQueryWrapper<OrderSettlement>().eq(OrderSettlement::getUserId, orderSettlementHistory.getUserId()).eq(OrderSettlement::getOrderNumber, orderSettlementHistory.getOrderNumber()));
                    orderSettlement.setPayNo(orderSettlementHistory.getPayNo());
                    orderSettlement.setPayType(orderSettlementHistory.getPayType());
                    orderSettlementList.add(orderSettlement);
                }
                orderSettlementService.updateBatchById(orderSettlementList);
                ///
                List<OrderSettlement> orderSettlements = orderSettlementMapper.selectList(new LambdaQueryWrapper<OrderSettlement>().eq(OrderSettlement::getPayNo, payNo));
                OrderSettlement settlement = orderSettlements.get(0);
                List<String> orderNumbers = orderSettlements.stream().map(OrderSettlement::getOrderNumber).collect(Collectors.toList());
                // 订单已支付
                if (settlement.getPayStatus() == 1) {
                    log.info("订单已支付，settlement.id：{}", settlement.getSettlementId());
                    return Collections.emptyList();
                }
                // 修改订单结算信息
                if (orderSettlementMapper.updateToPay(payNo, bizPayNo, settlement.getVersion()) < 1) {
                    // 结算信息已更改
                    throw new YamiShopBindException("yami.modified.settlement.information");
                }
                // 将订单改为已支付状态
                orderMapper.updateByToPaySuccess(orderNumbers, payType);

                List<OrderItem> allOrderItem = new ArrayList<>();

                List<Order> orders = orderNumbers.stream().map(orderNumber -> {
                    Order order = orderMapper.getOrderAndOrderItemByOrderNumber(orderNumber);
                    allOrderItem.addAll(order.getOrderItems());
                    return order;
                }).collect(Collectors.toList());

                // 消息推送-支付成功
                notifyTemplateService.sendNotifyOfPaySuccess(orders);

                //如果是积分订单无需改变,不是则发送支付成功事件
                if (!Objects.equals(orders.get(0).getOrderType(), OrderType.SCORE.value())) {
                    eventPublisher.publishEvent(new PaySuccessOrderEvent(orders, allOrderItem, payNo));
                }
                return orders;
            }
        }
        // 查询支付记录
        RefundInfoDto refundInfo = new RefundInfoDto();
        refundInfo.setPayNo(temp.getPayNo());
        refundInfo.setBizPayNo(temp.getBizPayNo());
        String refundSn = String.valueOf(snowflake.nextId());
        refundInfo.setRefundSn(refundSn);
        refundInfo.setRefundAmount(temp.getPayAmount());
        refundInfo.setPayType(PayType.instance(temp.getPayType()));
        refundInfo.setNotifyUrl("/order/refund/result/" + temp.getPayType());
        refundInfo.setPayAmount(temp.getPayAmount());
        boolean refundSuccess = payManagerService.doRefund(refundInfo);
        if (refundSuccess) {
            ///
            RefundOrderSettlement refundOrderSettlement = new RefundOrderSettlement();
            refundOrderSettlement.setOrderNumber(temp.getOrderNumber());
            refundOrderSettlement.setOrderPayNo(temp.getPayNo());
            refundOrderSettlement.setRefundSn(refundSn);
            refundOrderSettlement.setPayType(temp.getPayType());
            refundOrderSettlement.setPayTypeName(temp.getPayTypeName());
            refundOrderSettlement.setRefundAmount(temp.getPayAmount());
            refundOrderSettlement.setOrderTotalAmount(temp.getPayAmount());
            refundOrderSettlement.setUserId(temp.getUserId());
            refundOrderSettlement.setRefundStatus(1);
            Date nowDate = new Date();
            refundOrderSettlement.setCreateTime(nowDate);
            refundOrderSettlement.setUpdateTime(nowDate);
            refundOrderSettlementService.save(refundOrderSettlement);
            ///
            // 查询退款结算记录
            RefundOrderSettlement refundOrderSettlement2 = refundOrderSettlementService.getOne(
                    new LambdaQueryWrapper<RefundOrderSettlement>().eq(RefundOrderSettlement::getRefundSn, refundSn));
            // 更新退款结算记录
            refundOrderSettlement2.setPayRefundId("");
            refundOrderSettlement2.setRefundStatus(2);
            refundOrderSettlementService.updateById(refundOrderSettlement2);
        }
        return new ArrayList<>();
    }


}
